<?php

namespace App\Console\Commands;

namespace App\Console\Commands;
use Exception;
use Swoole\Process;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;

class RealTimePush extends Command
{
    private $swoole;
    private $pid_file;
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'realtimePush {action}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '实时推送';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
        $this->pid_file = __DIR__ . '/../../../storage/logs/swoole_websocket_realtime.pid';
    }

    /**
     * Execute the console command.
     *
     * @return int
     */
    public function handle()
    {
        $action = $this->argument('action');
        switch ($action) {
            case 'stop':   //停止命令
                $this->stop();
                break;
            case 'start':  //启动命令
                $this->start();
                break;
            default:
                $this->error('没有' . $action . '这个命令');
                break;
        }
    }


    // 启动服务
    public function start()
    {
        $pid = $this->getPid();
        //检测服务是否启动
        if ($pid && Process::kill($pid, 0)) {
            $this->error('服务已启动');
            exit;
        }
        //创建websocket服务，监听ip:端口
        $this->swoole = new \swoole_websocket_server("0.0.0.0", 9501);
        $this->swoole->set([
            //60秒检测一次,一个连接如果300秒内未向服务器发送任何数据，此连接将被强制关闭
            'heartbeat_check_interval' => 60, 'heartbeat_idle_time' => 300,
            //进程id存储路径
            'pid_file' => $this->pid_file,
        ]);
        //监听WebSocket连接打开事件
        $this->swoole->on('open', [$this, 'open']);
        //监听WebSocket消息事件
        $this->swoole->on('message', [$this, 'message']);
        //监听WebSocket主动推送消息事件
        $this->swoole->on('request', [$this, 'request']);
        //监听WebSocket连接关闭事件
        $this->swoole->on('close', [$this, 'close']);
        //启动事件
        $this->swoole->start();
    }

    // 建立连接
    public function open($swoole, $request)
    {
        //$request->fd是连接当前页面的ID
//        if (isset($request->get) && isset($request->get['token'])) {
            $swoole->push($request->fd, json_encode(['code' => 200, 'msg' =>'连接成功']));
//        } else {
//            $swoole->push($request->fd, json_encode(['code' => 400, 'msg' =>'没有登录']));
//            //断开连接
//            $swoole->close($request->fd);
//        }
    }

    //接收前端发送的消息
    public function message($swoole, $frame)
    {
        $swoole->push($frame->fd, '已收到发送的消息');
    } 

    // 接收服务器请求
    public function request($request, $response)
    {
        try {
            //请求的数据
            $post = $request->post;
            //拼接redis的key
            $key = 'realTimePush' . date('Ymd');
            $redis = new \Redis();
            $redis->connect('127.0.0.1', 6379);
            $redis->auth('passworld');
            $redis->select(0);
            $datas = [];
            //获取所有连接fd
            $clients = $this->swoole->getClientList();
            //获取队列的长度
            $num = $redis->lLen($key);
            //连接fd是空 队列里没有推送内容
            if (!empty($clients) && $num > 0) {
                //循环取出数据
                while ($num > 0) {
                    $data = $redis->rpop($key);
                    if (!empty($data)) {
                        $datas[] = json_decode($data, true);
                    }
                    $num--;
                }
                //推送的数据
                $result = json_encode(['code' => 200, 'msg' => '成功', 'data' => $datas]);
                //循环推送数据到前端
                foreach ($clients as $fd) {
                    if ($this->swoole->isEstablished($fd)) {
                        if ($this->swoole->push($fd, $result)) {
                            //Log::info('推送成功');
                        }
                    }
                }
            }
            $redis->close();
            return true;
        } catch (Exception $e) {
            Log::error('推送：' . $e->getMessage());
            return false;
        }
    }

    // 关闭连接
    public function close($swoole, $fd)
    {
        $swoole->close($fd);
    }
    // 服务停止
    public function stop()
    {
        if (!$pid = $this->getPid()) {
            $this->error('没有服务id');
            exit;
        }
        //关闭服务
        if (Process::kill($pid)) {
            $this->info('服务已停止');
            exit;
        }
        $this->info('停止服务失败');
    }

    // 获取进程pid
    private function getPid()
    {
        return file_exists($this->pid_file) ? file_get_contents($this->pid_file) : false;
    }

}
